/*
    This file is part of Raptor.

    Raptor is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Raptor is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Raptor.  If not, see <http://www.gnu.org/licenses/>.

 */

#include "rs-layer_com.h"


pluginUrlContainer::pluginUrlContainer()
{
    reHost = QRegExp("^rs-layer.com$");
    reLink = QRegExp("^http://rs-layer.com/(?:.*)$");

    connect(&http, SIGNAL(requestFinished(int, bool)), this, SLOT(slot_http_requestFinished(int, bool)));
    connect(&http, SIGNAL(readyRead(const QHttpResponseHeader &)), this, SLOT(slot_http_readyRead(const QHttpResponseHeader &)));
    connect(&http, SIGNAL(dataReadProgress(int, int)), this, SLOT(slot_http_dataReadProgress(int, int)));
    connect(&http, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(slot_http_sslErrors(const QList<QSslError> &)));

    reCaptcha = QRegExp("<input type=\"hidden\" name=\"image_name\" value=\"([^\"]*)\" id=\"image_name\" />");
    reCaptchaFile = QRegExp("<img src=\"([^\"]*)\"(?:[^>]*)id=\"captcha_image\"/>");
    reIp = QRegExp("<td><font SIZE=\"3\" COLOR=\"#FFFFFF\" FACE=\"Helvetica, Arial\"><b>Geteilte IP-Adresse</b></font></td>'");
    reGetFile = QRegExp("getFile\\('([^']*)'\\);");
    reFrame = QRegExp("<iframe(?:[^>]*)src=\"([^\"]*)\">");
}

void pluginUrlContainer::setProxy(QNetworkProxy const& proxy)
{
    //todo:
    Q_UNUSED(proxy);
    //this->http.setProxy(QNetworkProxy(proxy));
}

void pluginUrlContainer::start(QUrl const& url, QString const& captchaDir)
{
    _url = url;
    this->_abort = false;
    step = 0;
    links.clear();

    maskedLinks.clear();
    framedLinks.clear();

    this->_captchaDir = captchaDir;
    waitingId = request(url, "GET", QByteArray(), QMap<QString, QString>());
}

void pluginUrlContainer::abort()
{
    this->_abort = true;
    this->http.abort();
}

void pluginUrlContainer::setCaptcha(QString const& captcha)
{
    if(step == 2)
    {
        step = 3;

        QByteArray post = "image_name=" + QUrl::toPercentEncoding(imageName) + "&captcha_input=" + QUrl::toPercentEncoding(captcha) + "&action=";
        QMap<QString, QString> header;
        header.insert("Content-Type", "application/x-www-form-urlencoded");

        waitingId = request(_url, "POST", post, header);
    } else
    {
        this->_errorString = tr("Wrong time for captcha.");
        finish(true);
    }
}

bool pluginUrlContainer::isValidUrl(QUrl const& url)
{
    if(reLink.indexIn(url.toString()) != -1)
    {
        return true;
    }

    return false;
}

int pluginUrlContainer::request(QUrl const& url, QString const& method, QByteArray const& post, QMap<QString, QString> const& headerData, QIODevice *io)
{
    response = "";

    QHttpRequestHeader header(method, url.path());
    header.setValue("Host", url.host());


    QMap<QString, QString>::const_iterator it = headerData.constBegin();
    for(;it!=headerData.constEnd(); ++it)
    {
        header.setValue(it.key(), it.value());
    }

    if(this->cookie != "") header.setValue("Cookie", this->cookie);

    if(url.toString().left(5) == "https")
    {
        this->http.setHost(url.host(), QHttp::ConnectionModeHttps);
    } else
    {
        this->http.setHost(url.host());
    }

    if(io == 0)
    {
        return this->http.request(header, post);
    } else
    {
        return this->http.request(header, post, io);
    }
}

void pluginUrlContainer::finish(bool const& error)
{    
    maskedLinks.clear();
    framedLinks.clear();

    emit progressChanged(100);
    emit finished(links, error);
}

QString pluginUrlContainer::fromUnicode(QString const& str)
{
    QRegExp rx("&#(\\d*);");
    QString tmpStr = "";

    int pos = 0;
    while((pos = rx.indexIn(str, pos)) != -1)
    {
        tmpStr += QChar(rx.cap(1).toInt());

        pos += rx.matchedLength();
    }

    return tmpStr;
}

void pluginUrlContainer::loadCaptcha()
{
    if(reCaptcha.indexIn(page) != -1)
    {
        imageName = reCaptcha.cap(1);

        if(reCaptchaFile.indexIn(page) != -1)
        {
            QString captchaUrl = "http://rs-layer.com/" + reCaptchaFile.cap(1);

            step = 1;

            this->_captchaFile = new QTemporaryFile(this->_captchaDir + QDir::separator() + "rs-layer_com" + "_XXXXXX.png");
            this->_captchaFile->setAutoRemove(false);

            if(this->_captchaFile->open())
            {
                waitingId = request(QUrl(captchaUrl), "POST", QByteArray(), QMap<QString, QString>(), this->_captchaFile);
            } else
            {
                this->_errorString = tr("Cannot create captcha file.");
                finish(true);
            }
        } else
        {
            this->_errorString = tr("Captcha not found.");
            finish(true);
        }
    } else
    {
        this->_errorString = tr("Captcha not needed.");
        finish(true);
    }
}

//slots ->
void pluginUrlContainer::slot_http_requestFinished(int id, bool error)
{
    Q_UNUSED(error);

    if(this->_abort)
    {
        if(this->_captchaFile->isOpen()) this->_captchaFile->close();
        this->_errorString = http.errorString();
        finish(true);
        return;
    }

    if(waitingId != id) return;
    page = QString(response);

    switch(step)
    {
        default:
        case 0:
        {
            loadCaptcha();
            break;
        }

        case 1:
        {
            if(this->_captchaFile)
            {
                this->_captchaFile->close();
                step = 2;
                emit captcha(this->_captchaFile->fileName());
            } else
            {
                this->_errorString = tr("Captcha file does not exist.");
                finish(true);
            }
            break;
        }

        case 2:
        {

            break;
        }

        case 3:
        {
            if(reCaptchaFile.indexIn(page) != -1)
            {
                if(this->_captchaFile)
                {
                    this->_captchaFile->remove();
                }

                loadCaptcha();
                break;
            }

            if(reGetFile.indexIn(page) != -1)
            {
                int pos = 0;

                while((pos = reGetFile.indexIn(page, pos)) != -1)
                {
                    maskedLinks.append(reGetFile.cap(1));

                    pos += reGetFile.matchedLength();
                }

                if(maskedLinks.size() > 0)
                {
                    step = 4;
                    counter = 1;

                    QString tmpLink = "http://rs-layer.com/rsl-" + maskedLinks.at(0) + ".html";

                    waitingId = request(QUrl(tmpLink), "GET", QByteArray(), QMap<QString, QString>());
                } else
                {
                    finish(false);
                }
            } else
            {
                this->_errorString = tr("No files found.");
                finish(true);
            }

            break;
        }

        case 4:
        {
            int tmpProgress = (100 * counter) / maskedLinks.size();

            if(tmpProgress < 0) tmpProgress = 0;
            if(tmpProgress > 100) tmpProgress = 100;

            emit progressChanged(tmpProgress);

            if(reFrame.indexIn(page) != -1)
            {
                framedLinks.append(reFrame.cap(1));
            }

            if(counter < maskedLinks.size())
            {
                QString tmpLink = "http://rs-layer.com/rsl-" + maskedLinks.at(counter) + ".html";
                ++counter;

                waitingId = request(QUrl(tmpLink), "GET", QByteArray(), QMap<QString, QString>());
            } else
            {
                for(int i=0; i<framedLinks.size(); ++i)
                {
                    links.append(fromUnicode(framedLinks.at(i)));
                }

                finish(false);
            }

            break;
        }
    }
}

void pluginUrlContainer::slot_http_readyRead(const QHttpResponseHeader & resp)
{
    Q_UNUSED(resp);
    response.append(this->http.readAll());
}

void pluginUrlContainer::slot_http_dataReadProgress(int done, int total)
{
    Q_UNUSED(done);
    Q_UNUSED(total);
}

void pluginUrlContainer::slot_http_sslErrors(const QList<QSslError> & errors)
{
    //todo:
    Q_UNUSED(errors);
    this->http.ignoreSslErrors();
}
//<- slots

Q_EXPORT_PLUGIN2(serienjunkies_org, pluginUrlContainer);
